package com.crl.manager
{
	import com.crl.events.VolumeEvent;
	
	import flash.display.Sprite;
	import flash.events.EventDispatcher;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.utils.Dictionary;
	
	
	/**
	 * Generic Sound Manager to handle site wide sound management. Sound
	 * API's are much different in AS3 so this is should be used.
	 * 
	 * from:
	 * com.floss.sound.SoundManager
	 */
	public class SoundManager extends EventDispatcher
	{
		
		/**
		 * Singleton instance.
		 */
		private static var instance:SoundManager;
		
		/**
		 * Sounds stored in the manager.
		 */
		private var _soundDic:Dictionary;
		
		/**
		 * Internal volume indicator. Used for volume toggling.
		 */
		private var _volume:Number;
		
		/**
		 * Sounds objects with transforms store. 
		 */
		private var _sndObjectsWithTransforms:Dictionary;
		
		/**
		 * Single transform used internally when playing any sound
		 * This is passed to the sound object to set it's volume.
		 */
		private var _mainTransform:SoundTransform;
		
		/**
		 * Array of sounds transforms currently being used by playing sounds.
		 */
		private var _soundTransforms:Array;
		
		/**
		 * Any sound currently playing.
		 */
		private var _playingSounds:Array;
		
		/**
		 * Limit duplicate playing 'loop' sounds to 1.
		 */
		public var limitDuplicatesTo1:Boolean;
		
		public var overrideCustomVolumesIfVolumeIs0:Boolean;
		
		/**
		 * Singleton SoundManager
		 */
		public function SoundManager()
		{
			if(instance)
				throw new Error("SoundManager is a singleton, call SoundManager.gi() for the instance.");
			
			instance = this;
			_soundDic = new Dictionary();
			_sndObjectsWithTransforms = new Dictionary();
			_volume = 0;
			_mainTransform = new SoundTransform(1,0);
			_playingSounds = [];
			_soundTransforms = [];
		}
		
		/**
		 * Public access to the singleton.
		 */
		public static function gi():SoundManager
		{
			if(instance == null)
			{
				instance = new SoundManager();
			}
			return instance;
		}
		
		/**
		 * Add a sound into the sound manager.
		 * @param		String		Any unique identifier to give to the sound.
		 */
		public function addSound(name:String,snd:Sound):void
		{
			_soundDic[name] = snd;
		}
		
		/**
		 * Add a sprite to control it's sound.
		 * @paraam		Sprite		Any sprite you want to control it's volume on.
		 */
		public function addSprite(obj:Sprite):void
		{
			_sndObjectsWithTransforms[obj] = obj;
		}
		
		/**
		 * Remove a sound from the manager.
		 * @param		String		The unique sound identifier.
		 */
		public function removeSound(name:String):void
		{
			delete (_soundDic[name]);
		}
		
		/**
		 * Play a sound already stored.
		 * @param	String		The unique name used when called addSound
		 * @param	Number		The start offset in seconds.
		 * @param	int			The number of times to loop the sound.
		 */
		public function playSound(name:String,startOffset:Number = 0,loopCount:int = 0):void
		{
			var snd:Sound = Sound(_soundDic[name]);
			_playingSounds[name] = snd.play(startOffset,loopCount,_mainTransform);
		}
		
		/**
		 * Play a sound with a custom volume.
		 * @param		String		The unique identier used with addSound
		 * @param		Number		The start offset
		 * @param		int			The number of times to loop the sound.
		 * @param		Number		The custom volume to play the sound at.
		 */
		public function playSoundWithCustomVolume(name:String,startOffset:Number = 0, loopCount:int = 0, volume:Number = 0):void
		{
			var st:SoundTransform = new SoundTransform(volume,0);
			var snd:Sound = Sound(_soundDic[name]);
			_soundTransforms[name] = st;
			if(_mainTransform.volume == 0 && overrideCustomVolumesIfVolumeIs0)
			{
				st.volume = 0;
				_playingSounds[name] = snd.play(startOffset,loopCount,st);
			}
			else
			{
				
				_playingSounds[name] = snd.play(startOffset,loopCount,st);
			}
		}
		
		/**
		 * Stop a sound
		 * @param		The unique identifer used when called playSound, or playSoundWithCustomVolume
		 */
		public function stopSound(name:String):void
		{
			try
			{
				var ch:SoundChannel = SoundChannel(_playingSounds[name]);
				ch.stop();
			}
			catch(e:*){}
		}
		
		/**
		 * Stop all sounds playing through the SoundManager.
		 */
		public function stopAllSounds():void
		{
			for each(var ch:SoundChannel in _playingSounds)
			{
				ch.stop();
			}
		}
		
		/**
		 * Set the global volume on all objects registered.
		 * @param		Number		The volume level.
		 */
		public function set volume(level:Number):void
		{
			_mainTransform.volume = level;
			for each(var obj:* in _sndObjectsWithTransforms)
			{
				obj.soundTransform.volume = _mainTransform.volume;
			}
			dispatchEvent(new VolumeEvent(_mainTransform.volume));
		}
		
		/**
		 * Toggle the current volume with 0.
		 */
		public function toggleVolume():void
		{			
			var tmp1:Number = _volume;
			var tmp2:Number = _mainTransform.volume;
			_mainTransform.volume = tmp1;
			_volume = tmp2;
			dispatchEvent(new VolumeEvent(_mainTransform.volume));
		}
	}
}